/*
 * luabase.c
 *
 * Copyright (C) 2011 - Dr.NP
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * @version luabase.c 1.0.0
 * @package exts/luabase
 * @author Dr.NP <np@bsgroup.org>
 * @update 05/30/2011
 */

/**
 * Standard runtime extension
 * BSP.Package and LUA support
 *
 * === CHANGELOG ===
 * [05/30/2011] - Creation
 */

#include "../../bsp.h"
#include "../../libs/app/bsp_app.h"
#include "../../libs/app/bsp_script.h"

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>

#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

#include "luabase.h"

void luabase_on_load(int);
void luabase_on_unload(int);
void luabase_on_conn(int);
void luabase_on_close(int);
size_t luabase_on_data(int, char *, size_t);
void luabase_on_error(int);

struct bsp_ext_entry_t entry = {
    luabase_on_load, 
    luabase_on_unload, 
    luabase_on_conn, 
    luabase_on_close, 
    luabase_on_data, 
    luabase_on_error
};
BSP_EXTENSION bsp_luabase_raw = {
    0, 
    "luabase_raw", 
    &entry, 
    NULL
};

void luabase_on_load(int app_id)
{
    struct app_t *a = get_app(app_id);
    struct script_t *s = a ? get_script(a->script_id) : NULL;

    if (s)
    {
        if (1 == s->load_times)
        {
            // First load
            lua_getglobal(s->main_state, LUABASE_FUNC_ON_LOAD);
            if (lua_pcall(s->main_state, 0, 0, 0))
            {
                debug_info("LUA state : Script <%s> has no available function %s\n", s->script_filename, LUABASE_FUNC_ON_LOAD);
            }
        }

        else
        {
            lua_getglobal(s->main_state, LUABASE_FUNC_ON_RELOAD);
            if (lua_pcall(s->main_state, 0, 0, 0))
            {
                debug_info("LUA state : Script <%s> has no available function %s\n", s->script_filename, LUABASE_FUNC_ON_RELOAD);
            }
        }
    }
    
    return;
}

void luabase_on_unload(int app_id)
{
    struct app_t *a = get_app(app_id);
    struct script_t *s = a ? get_script(a->script_id) : NULL;

    if (s)
    {
        lua_getglobal(s->main_state, LUABASE_FUNC_ON_UNLOAD);
        if (lua_pcall(s->main_state, 0, 0, 0))
        {
            debug_info("LUA state : Script <%s> has no available function %s\n", s->script_filename, LUABASE_FUNC_ON_UNLOAD);
        }
    }
    
    return;
}

void luabase_on_conn(int clt_id)
{
    struct client_t *c = get_client(clt_id);
    struct server_t *srv = c ? get_server(c->srv_id) : NULL;
    struct app_t *a = srv ? get_app(srv->app_id) : NULL;
    struct script_t *s = a ? get_script(a->script_id) : NULL;
    struct lua_State *ls = s->worker_states[c->worker_id];
    
    if (s && ls)
    {
        lua_getglobal(ls, LUABASE_FUNC_ON_CONN);
        lua_pushnumber(ls, clt_id);
        lua_pcall(ls, 1, 0, 0);
    }
    
    return;
}

void luabase_on_close(int clt_id)
{
    struct client_t *c = get_client(clt_id);
    struct server_t *srv = c ? get_server(c->srv_id) : NULL;
    struct app_t *a = srv ? get_app(srv->app_id) : NULL;
    struct script_t *s = a ? get_script(a->script_id) : NULL;
    struct lua_State *ls = s->worker_states[c->worker_id];
    
    if (s && ls)
    {
        lua_getglobal(ls, LUABASE_FUNC_ON_CLOSE);
        lua_pushnumber(ls, clt_id);
        lua_pcall(ls, 1, 0, 0);
    }
    
    return;
}

size_t luabase_on_data(int clt_id, char *data, size_t len)
{
    int ret = 0;
    
    struct client_t *c = get_client(clt_id);
    struct server_t *srv = c ? get_server(c->srv_id) : NULL;
    struct app_t *a = srv ? get_app(srv->app_id) : NULL;
    struct script_t *s = a ? get_script(a->script_id) : NULL;
    struct lua_State *ls = s->worker_states[c->worker_id];

    if (s && ls)
    {
        lua_getglobal(ls, LUABASE_FUNC_ON_DATA);
        lua_pushnumber(ls, clt_id);
        lua_pushlstring(ls, data, len);
        lua_pushnumber(ls, len);
        lua_pcall(ls, 3, 1, 0);

        ret = lua_tonumber(ls, -1);
        lua_pop(ls, 1);
    }
    
    return ret;
}

void luabase_on_error(int clt_id)
{
    struct client_t *c = get_client(clt_id);
    struct server_t *srv = c ? get_server(c->srv_id) : NULL;
    struct app_t *a = srv ? get_app(srv->app_id) : NULL;
    struct script_t *s = a ? get_script(a->script_id) : NULL;
    struct lua_State *ls = s->worker_states[c->worker_id];
    
    if (s && ls)
    {
        lua_getglobal(ls, LUABASE_FUNC_ON_ERROR);
        lua_pushnumber(ls, clt_id);
        lua_pcall(ls, 1, 0, 0);
    }
    
    return;
}
